<template>
    <div class="containers" ref="content">
        <div class="canvas">
            <div class="bpmn" ref="canvas">

            </div>
            <Tool class="tool">
                <el-button type="success" circle icon="el-icon-download" size="mini"></el-button>
            </Tool>
        </div>
        <div class="panel" :class="{'panel-toggle':toggle}">
            <div class="left" @click="toggle=!toggle">
                <i :class="toggle?'el-icon-d-arrow-right':'el-icon-d-arrow-left'"></i>
            </div>
            <component v-if="propsComponent&&toggle" :is="propsComponent" :element="element" :key="key"></component>
        </div>

    </div>
</template>

<script>
    import CustomModeler from './customModeler'
    import customTranslate from '@/i18n/customTranslate/customTranslate'
    import flowableModdleDescriptor from '@/assets/flowable'
    import defaultXml from '@/config/defaultXml'
    import UserTaskProperties from '@/components/Properties/UserTaskProperties'
    import ProcessProperties from '@/components/Properties/ProcessProperties'
    import SubProcessProperties from '@/components/Properties/SubProcessProperties'
    import SequenceFlowProperties from '@/components/Properties/SequenceFlowProperties'
    import EndEventProperties from '@/components/Properties/EndEventProperties'
    import StartEventProperties from '@/components/Properties/StartEventProperties'
    import Tool from '@/components/Tool/Tool'
    const noop =function () {
    }
    export default {
        name:'BpmModel',
        props:{
            model:{
                type:Object,
                default(){
                    return {}
                }
            },
            deptOptions:{
                type:Array,
                default(){
                    return []
                }
            },
            userList:{
                type:Function,
                default(){
                    return noop
                }
            },
            postOptions:{
                type:Array,
                default(){
                    return []
                }
            },
        },
        components: {
            UserTaskProperties,
            SequenceFlowProperties,
            EndEventProperties,
            StartEventProperties,
            SubProcessProperties,
            Tool,
            ProcessProperties
        },
        provide: function () {
            return {
                bpmnModeler: this.getBpmnModeler,
                modeling: this.getModeling,
                elementRegistry: this.getElementRegistry,
                bpmnFactory: this.getBpmnFactory,
                commandStack: this.getCommandStack,
                canvas: this.getCanvas,
                setKey: this.setKey,
                saveModel: this.saveModel,
                deptList: this.deptList,
                postList: this.postList,
                userListApi: this.userList,
            }
        },
        data() {
            return {
                // bpmn建模器
                propsComponent: '',
                bpmnModeler: null,
                element: null,
                container: null,
                key: null,
                canvas: null,
                toggle:true,
            }
        },
        watch:{
            'model.xml'(val){
                this.createNewDiagram()
            }
        },
        methods: {
            getBpmnModeler() {
                return this.bpmnModeler
            },
            deptList() {
                return this.deptOptions
            },
            postList() {
                return this.postOptions
            },
            setKey() {
                if(this.key){
                    this.key = new Date().getTime()
                }
            },
            saveModel(res) {
                console.log(res.xml)
                this.$emit('saveModel',res)
            },
            getModeling() {
                if (!this.bpmnModeler) {
                    return
                }
                return this.bpmnModeler.get('modeling')
            },
            getElementRegistry() {
                if (!this.bpmnModeler) {
                    return
                }
                return this.bpmnModeler.get('elementRegistry')
            },
            getCanvas() {
                if (!this.bpmnModeler) {
                    return
                }
                return this.bpmnModeler.get('canvas')
            },
            getBpmnFactory() {
                if (!this.bpmnModeler) {
                    return
                }
                return this.bpmnModeler.get('bpmnFactory')
            },
            getCommandStack() {
                if (!this.bpmnModeler) {
                    return
                }
                return this.bpmnModeler.get('commandStack')
            },
            getShape(id) {
                var elementRegistry = this.getElementRegistry()
                return elementRegistry.get(id)
            },
            getComponentByEleType(type) {
                return `${type.replace(/^bpmn:/, '')}Properties`
            },
            createNewDiagram() {
                const bpmnXmlStr = this.model.xml||defaultXml
                // 将字符串转换成图显示出来
                this.bpmnModeler.importXML(bpmnXmlStr).then(res => {
                    //导入完成添加监听事件
                    this.addModelerListener()
                    this.addEventBusListener()
                    this.getCanvas().getRootElement().businessObject.id =  this.model.key||'eflow_1'
                    this.getCanvas().getRootElement().businessObject.name =  this.model.name||'eflow_1'
                })
            },
            addModelerListener() {
                // 监听 modeler
                const events = ['shape.added', 'shape.move.end', 'shape.removed']
                events.forEach((event) => {
                    this.bpmnModeler.on(event, e => {
                        var shape = e.element || e.shape
                        //解决添加线的名称报错问题
                        if (shape.type === 'label') {
                            return
                        }
                        this.key = shape.id
                        if (['shape.added', 'shape.move.end'].includes(event)) {
                            // 展示新增图形的属性
                            this.propsComponent = this.getComponentByEleType(shape.type)
                            this.element = shape
                        } else if (event === 'shape.removed') {
                            this.key = 'Process'
                            this.propsComponent = 'ProcessProperties'
                        }
                    })
                })
            },
            addEventBusListener() {
                // 监听 element
                const eventBus = this.bpmnModeler.get('eventBus')
                eventBus.on('element.click', (e) => {
                    let element = e.element
                    //解决编辑label组件的问题，让他直接选中他的业务组件
                    if (element.type === 'label') {
                        //获取lable的业务组件
                        element = this.getShape(element.businessObject.id)
                    }
                    this.propsComponent = this.getComponentByEleType(element.type)
                    this.key = element.id
                    this.element = element
                })
            },
            initBpmn() {
                const canvas = this.$refs.canvas
                const customTranslateModule = {
                    translate: ['value', customTranslate]
                }
                this.bpmnModeler = new CustomModeler({
                    container: canvas,
                    //添加快捷键
                    keyboard: {
                        bindTo: window
                    },
                    additionalModules: [
                        customTranslateModule,
                    ],
                    //模块拓展，拓展activiti的描述
                    moddleExtensions: {
                        flowable: flowableModdleDescriptor
                    }
                })

                //重写撤销方法，修改key使得右边面板实时刷新
                const  commandStack = this.bpmnModeler.get('commandStack')
                const undo = commandStack.undo.bind( commandStack)
                this.bpmnModeler.get('commandStack').undo = ()=>{
                    undo()
                   this.setKey()
                }
                const redo = commandStack.redo.bind( commandStack)
                this.bpmnModeler.get('commandStack').redo = ()=>{
                    redo()
                   this.setKey()
                }

                this.createNewDiagram()

            }
        },
        mounted() {
            this.initBpmn()
        }
    }

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" scoped>
    /*左边工具栏以及编辑节点的样式*/
    @import '~bpmn-js/dist/assets/diagram-js.css';
    @import '~bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
    @import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
    @import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
    /*右边工具栏样式*/
    .containers {
        position: absolute;
        width: 100%;
        height: 100%;
        display: flex;

    }

    .canvas {
        /*网格*/
        background-size: 10px 10px;
        -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
        background-image: linear-gradient(90deg, rgba(180, 180, 180, 0.15) 10%, rgba(0, 0, 0, 0) 10%),
        linear-gradient(rgba(180, 180, 180, 0.15) 10%, rgba(0, 0, 0, 0) 10%);

        width: 100%;
        height: 100%;
        box-sizing: border-box;
        -moz-box-sizing: border-box;
        border-right: 1px solid #eee;
        position: relative;
        display: flex;

        .bpmn {
            width: 100%;
            height: 100%;
        }

        .tool {
            position: absolute;
            right: 80px;
            bottom: 20px;
        }
    }
    .panel-toggle{
        width: 600px;
    }
    .panel {
        position: relative;
        right: 0;
        top: 0;
        box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
        padding-left: 10px;
        padding-right: 10px;

        .left{
            display: flex;
            top: 50%;
            left: -17px;
            background: #dfd7d7;
            height: 60px;
            position: absolute;
            i{
                align-self: center;
            }
        }
    }

</style>
